package bancosys.tec.persist.fieldhistory;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import jmine.tec.persist.PersistMessages;
import bancosys.tec.persist.exception.PersistenceException;

/**
 * @param <T> tipo do dado a ser guardado histórico.
 * @created 27/09/2007
 * @author Gustavo Almeida
 */
public class HistoryHolder<T> implements Serializable {
    private T value;

    private List<T> history = new ArrayList<T>();

    /**
     * Define o valor.
     * 
     * @param value valor.
     */
    public void setValue(T value) {
        this.value = value;
        this.history.add(value);
    }

    /**
     * Devolve o valor.
     * 
     * @return o valor.
     */
    public T getValue() {
        return this.value;
    }

    /**
     * Devolve o histórico do dado em uma lista onde o primeiro elemento é o valor mais velho e o último o mais novo.
     * 
     * @return o histórico do dado em uma lista onde o primeiro elemento é o valor mais velho e o último o mais novo.
     */
    public List<T> getHistory() {
        return this.history;
    }

    /**
     * Limpa o history, deixando apenas o valor atual.
     */
    public void reset() {
        this.history.clear();
        this.history.add(this.value);
    }

    /**
     * @param bean bean
     */
    public static void resetHistory(Object bean) {
        for (Class<?> clazz = bean.getClass(); !clazz.equals(Object.class); clazz = clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (HistoryHolder.class.isAssignableFrom(field.getType())) {
                    try {
                        HistoryHolder<?> historyHolder;
                        if (field.isAccessible()) {
                            historyHolder = (HistoryHolder<?>) field.get(bean);
                        } else {
                            field.setAccessible(true);
                            historyHolder = (HistoryHolder<?>) field.get(bean);
                            field.setAccessible(false);
                        }
                        if (historyHolder != null) {
                            historyHolder.reset();
                        }
                    } catch (IllegalArgumentException e) {
                        throw new PersistenceException(PersistMessages.ERROR_CLEANING_FIELD_HISTORY.create(field.getName(), bean), e);
                    } catch (IllegalAccessException e) {
                        throw new PersistenceException(PersistMessages.ERROR_CLEANING_FIELD_HISTORY.create(field.getName(), bean), e);
                    }
                }
            }
        }
    }
}
